home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / Font Handler / FontMemory.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  18.1 KB  |  618 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        FontMemory.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.                          This file contains routines for the memory 
  6.                         management of fonts on the printer
  7.  
  8.      Version:    Technology:    Quickdraw GX 1.1.x
  9.       
  10.      Copyright:    © 1991-1997 by Apple Computer, Inc., all rights reserved.
  11. */
  12.  
  13. #include <GXExceptions.h>
  14. #include "GXToPSBuildConfig.h"
  15. #include "GXPrintingUniverse.h"
  16. #include <Collections.h>
  17. #include "GXGraphics.h"
  18. #include "FontDatabase.h"
  19. #include "FontHandler.h"
  20. #include "FontHandlerPrivate.h"
  21. #include "FontHandlerVariations.h"
  22. #include "IOUtilities.h"
  23. #include <String.h>
  24. #include <MacMemory.h>
  25. #include <StdLib.h>
  26.  
  27. #ifdef resumeLabel
  28.     #undef resumeLabel
  29. #endif
  30. #define resumeLabel(exception)
  31.  
  32.  
  33.  
  34. /** Structure for sorting font memory usage **/
  35.  
  36. typedef struct {
  37.  
  38.     fhFont            theFont;                        // The snapshot font reference.
  39.     long                firstNonResident;        // For doc font, index of first printer font with no printer-resident glyphs.
  40.     long                prFontIndex;                // Printer font reference.
  41.     long                vmUsage;                        // How much memory does it use.
  42.     long                index;                            // Index of printer font.
  43.     Boolean            used;                                // Has this font already been picked for download?
  44.  
  45. } fontMemRec;
  46.  
  47. /*** Function to be passed into qsort routine ***/
  48. int SortComparison(const void *first, const void *second);
  49. int SortComparison(const void *first, const void *second)
  50.     {
  51.         fontMemRec        *entry1, *entry2;
  52.         
  53.         entry1 = (fontMemRec*)first;
  54.         entry2 = (fontMemRec*)second;
  55.         
  56.         if (entry1->vmUsage < entry2->vmUsage)
  57.             return(1);
  58.         else if (entry1->vmUsage == entry2->vmUsage)
  59.             return(0);
  60.         else
  61.             return(-1);    
  62.     }
  63.  
  64.  
  65.  
  66. //<FF>
  67. /**********************************************
  68.     
  69.         BiggestRemainingFont:
  70.         
  71.         Function returns the size
  72.         of the biggest remaining font (unused or excluded).
  73.         
  74.         fontMemRecords:        Sorted Array of font memory records to search.
  75.         n:                                Length of array.
  76.         excludeFont:            exclude entries with this font ref from search.
  77.                                                 pass nil if you don't care.
  78.         
  79.         
  80. ***********************************************/
  81. long BiggestRemainingFont(fontMemRec *fontMemRecords, long n, fhFont excludeFont);
  82. long BiggestRemainingFont(fontMemRec *fontMemRecords, long n, fhFont excludeFont)
  83.     {
  84.         long                    i;
  85.         fontMemRec        *pMemRec = fontMemRecords;
  86.         for (i = 0; i < n; ++i) {
  87.  
  88.             /** the first unused one is the biggest since the array is sorted. **/
  89.             if ((!pMemRec->used) && ((pMemRec->theFont != excludeFont) || (excludeFont == nil)))
  90.                 break;
  91.             
  92.             ++pMemRec;
  93.             
  94.         }//end for
  95.     
  96.         if (i == n)
  97.             return(0);
  98.         else
  99.             return(pMemRec->vmUsage);
  100.     
  101.     }//BiggestReaminingFont
  102.  
  103.  
  104.  
  105. //<FF>
  106. /**********************************************
  107.  
  108.     Function: FHFindDocLevelFonts
  109.     
  110.     Function goes through the list of printer fonts and
  111.     figures out which ones should be downloaeded at the document
  112.     level (permanent fonts).
  113.     
  114.     The document level fonts will be those fonts that fit into 
  115.     memory and still leave enough room for the largest remaining
  116.     printer-font.
  117.     
  118.     Wow, this is a long routine, I should try to break it up in 
  119.     the next release.
  120.     
  121. ***********************************************/
  122. OSErr FHFindDocLevelFonts(TFontHandlerHdl hFHRec)
  123.     {
  124.         OSErr                            status;
  125.         long                            nDocFonts;                                // number of fonts in the document.
  126.         long                            nPrFonts;                                    // number of printer fonts in document.
  127.         long                            nDocFontsDL;                            // Number of document fonts that must be downloaded
  128.         long                            nPrFontsDL;                                // Number of printer fonts that must be downloaded.
  129.         Boolean                        hasDLFont;                                // Has a downloaded font.
  130.         long                            offset;                                        // Offset to a printer font record.
  131.         TPrinterFontRec        *printerFont;
  132.         TFontDbase                fontDbase;
  133.         fhFont                        theFont;
  134.         long                            remainingVM;                            // Keep track of VM on printer for sorting through.
  135.         fontMemRec                *docFontMemRecords;                // Array of document-font memory records for sorting.
  136.         fontMemRec                *prFontMemRecords;                // Array of printer-font memory records for sorting.
  137.         fontMemRec                *pDocFontMemRec;                    // Pointer to one of these things for doc.
  138.         fontMemRec                *pPrFontMemRec;                        // Pointer to one of these things    for printer.
  139.         long                            biggestRemaining;                    // Size of biggest remaining font in list.
  140.         Handle                        h;
  141.         long                            i, j, n;
  142.                 
  143.  
  144.         fontDbase = (*hFHRec)->docDbase;
  145.         nPrFonts = (*hFHRec)->numPrFonts;
  146.         nDocFonts = FHCountSnapshots(hFHRec);
  147.                 
  148.         /** Allocate a work handle for sorting the font vm usage **/
  149.         
  150.         status = FHSetWorkHandleSize(hFHRec, (nDocFonts + nPrFonts) * sizeof(fontMemRec), 0, &h);
  151.         nrequire(status, failed_WrkSpace);
  152.         HLockHi(h);
  153.         docFontMemRecords = (fontMemRec*)*h;
  154.         prFontMemRecords = docFontMemRecords + nDocFonts;
  155.         
  156.         pDocFontMemRec = docFontMemRecords;
  157.         pPrFontMemRec = prFontMemRecords;
  158.         nDocFontsDL = 0;
  159.         nPrFontsDL = 0;
  160.         
  161.         /*******
  162.             Build the arrays of printer and document font memory usage,
  163.             only for fonts that must be downloaded
  164.         *******/
  165.         for (i = 1; i <= nDocFonts; ++i) {
  166.         
  167.             /** Get the next document snapshot font **/
  168.             
  169.             status = FHGetIndexedSnapshot(hFHRec, i, &theFont);
  170.             nrequire(status, failed_GetFont);
  171.             
  172.             /** Get the number of printer fonts for this document font **/
  173.             n = FHCountPrinterFonts(hFHRec, theFont);
  174.  
  175.             /** Get all of the non-resident (downloaded) printer fonts for the document font **/        
  176.             hasDLFont = false;
  177.             for (j = 0; j < n; ++j) {
  178.  
  179.                 status = FHGetIndexedPrinterFont(hFHRec, theFont, j, &printerFont, &offset);
  180.                 nrequire(status, failed_GetItem);
  181.                                 
  182.                 /* We don't have to do anything special for fonts on printer or fonts that can't be used */
  183.                 if ( !( printerFont->info & (fontIsInPrinter + fontCantBeUsed) )  ){
  184.                 
  185.                     pPrFontMemRec->theFont = theFont;
  186.                     pPrFontMemRec->prFontIndex = j;
  187.                     pPrFontMemRec->vmUsage = printerFont->vmUsage;
  188.                     pPrFontMemRec->used = false;
  189.                     pPrFontMemRec->index = j;
  190.                     ++pPrFontMemRec;
  191.                     ++nPrFontsDL;
  192.                     
  193.                     if (!hasDLFont) {
  194.                 
  195.                         hasDLFont = true;
  196.                         pDocFontMemRec->theFont = theFont;
  197.                         pDocFontMemRec->vmUsage = printerFont->docVMUsage + (n - 1) * kEncodingOverhead;
  198.                         pDocFontMemRec->used = false;
  199.                         pDocFontMemRec->prFontIndex = 0;
  200.                         pDocFontMemRec->firstNonResident = j;
  201.                         ++pDocFontMemRec;
  202.                         ++nDocFontsDL;
  203.                         
  204.                     }//end if
  205.                     
  206.                 }//end if
  207.                 
  208.             }//end for
  209.                                 
  210.         }//end for
  211.                 
  212.         /*** Now sort the arrays ***/
  213.                 
  214.         qsort( (void*)docFontMemRecords, nDocFontsDL, sizeof(fontMemRec), SortComparison);
  215.         qsort( (void*)prFontMemRecords, nPrFontsDL, sizeof(fontMemRec), SortComparison);
  216.  
  217.         /*****
  218.  
  219.             If there is not even enough memory for the biggest individual printer font,
  220.             then we can't print the document.  Bail out now.
  221.             
  222.         ******/
  223.         remainingVM = (*hFHRec)->printerVM;
  224.         
  225.         if ((nPrFontsDL > 0) &&  (prFontMemRecords[0].vmUsage > remainingVM)) {        /* the first one is biggest after sort */
  226.         
  227.             status = gxNotEnoughPrinterMemory;
  228.             #if DEBUGLEVEL > 1
  229.             dprintf(notrace, "Not even enough memory for one of the fonts!!, mem avail: %d, required: %d",
  230.                                 remainingVM, prFontMemRecords[0].vmUsage);
  231.             #endif
  232.             
  233.             nrequire(status, failed_noMemForFonts);
  234.         
  235.         }//end if
  236.         
  237.         
  238.         /*********************************************
  239.             Compute the set of permanent document fonts
  240.             
  241.             In this first pass, compute the document fonts that
  242.             can be downloaded premanently with all document glyphs
  243.             as opposed to ones just in the printer-font's encoding.
  244.             Other glyphs accessed by re-encoding.  This is useful because
  245.             memory overhead of an encoding is smaller than that of a complete font.
  246.  
  247.             So see which ones we can download this way, still leaving enough room for
  248.             the biggest printer-font. 
  249.             
  250.             See ERS for complete description of algorithm
  251.         *********************************************/
  252.  
  253.         pDocFontMemRec = docFontMemRecords;
  254.         i = 0;
  255.         while (i < nDocFontsDL) {
  256.         
  257.             theFont = pDocFontMemRec->theFont;
  258.             biggestRemaining = BiggestRemainingFont(prFontMemRecords, nPrFontsDL, theFont);
  259.             
  260.             /******
  261.                 Can the next document font fit into remaining VM and 
  262.                 leave enough room for biggest printer font?
  263.             ******/
  264.             if (biggestRemaining <= remainingVM - pDocFontMemRec->vmUsage) {
  265.                         
  266.                 /** If so, mark it as used and update printer-font records appropriately **/
  267.                 
  268.                 remainingVM -= pDocFontMemRec->vmUsage;        // Update remaining VM after this font is on printer.
  269.                 
  270.                 pDocFontMemRec->used = true;
  271.                 
  272.                 /** Loop over printer fonts for this document font and mark them with appropriate flags **/
  273.  
  274.                 n = FHCountPrinterFonts(hFHRec, theFont);
  275.                 for (j = pDocFontMemRec->firstNonResident; j < n; ++j) {
  276.                 
  277.                     status = FHGetIndexedPrinterFont(hFHRec, theFont, j, &printerFont, &offset);
  278.                     nrequire(status, failed_GetItem);
  279.                     
  280.                     printerFont->info |= fontIsPerm;                            // Font will be permanent.
  281.                     if (j == pDocFontMemRec->firstNonResident)
  282.                         printerFont->info |= fontHasAllDocGlyphs;        // first one will contain all doc glyphs. (except those on printer)
  283.                     else
  284.                         printerFont->info |= fontIsEncodingOnly;        // The rest will be reencodings of first.
  285.                 
  286.                 }//end for
  287.                 
  288.                 /** Now mark all the printer fonts for this font in the sorted array as used **/
  289.                 pPrFontMemRec = prFontMemRecords;
  290.                 for (j = 0; j < nPrFontsDL; ++j, ++pPrFontMemRec) {
  291.                 
  292.                     if (pPrFontMemRec->theFont == theFont)
  293.                         pPrFontMemRec->used = true;
  294.                                             
  295.                 }//end for
  296.             
  297.             } else if ( FHFontMayBe2Byte(FHGetSnapShotFont(hFHRec, theFont, nil) ) ) {
  298.                 
  299.                 /********************************
  300.                     If it was a 2 byte font that couldn't fit, then mark it as unusable.
  301.                     It is better to let Imaging Engine do bitmaps or something than to try
  302.                     to download and swap multiple encodings every couple of glyphs drawn.
  303.                     
  304.                     There is some code duplicated from above here that could lend itself
  305.                     to modularization.  Next time, I guess.
  306.                 *********************************/
  307.                     
  308.                 #if DEBUGLEVEL > 1
  309.                 dprintf(trace, "Font: %X is double-byte, and didn't fit in memory - marking for rasterization");
  310.                 #endif
  311.                 
  312.                 /* Mark all of the printer fonts for this document font as fontCantBeUsed */                
  313.                 n = FHCountPrinterFonts(hFHRec, theFont);
  314.                 for (j = pDocFontMemRec->firstNonResident; j < n; ++j) {
  315.                 
  316.                     status = FHGetIndexedPrinterFont(hFHRec, theFont, j, &printerFont, &offset);
  317.                     nrequire(status, failed_GetItem);
  318.                     printerFont->info |= fontCantBeUsed;
  319.                 
  320.                 }//end for
  321.                 
  322.                 /* Now mark entries in sorted array as used */
  323.                 
  324.                 pPrFontMemRec = prFontMemRecords;
  325.                 for (j = 0; j < nPrFontsDL; ++j, ++pPrFontMemRec) {
  326.                 
  327.                     if (pPrFontMemRec->theFont == theFont)
  328.                         pPrFontMemRec->used = true;
  329.                                             
  330.                 }//end for
  331.                 
  332.             } else {
  333.                 
  334.                 /********************************
  335.                     No room for any of reamining printer fonts if this 
  336.                     doc font is downloaded whole with all encodings. It wasn't
  337.                     a 2 byte font, break out of loop and handle as individual
  338.                     printer fonts.
  339.                 *********************************/
  340.                 break;
  341.                     
  342.             
  343.             }//end if
  344.  
  345.             ++pDocFontMemRec;
  346.             ++i;
  347.             
  348.         }//end while;
  349.         
  350.         
  351.         /*** Now check the list to see if any of the remaining printer fonts can be permanent ***/
  352.         
  353.         pPrFontMemRec = prFontMemRecords;
  354.         for (i = 0; i < nPrFontsDL; ++i) {
  355.         
  356.             if (!pPrFontMemRec->used) {                    // If the font is still unused:
  357.             
  358.                 biggestRemaining = BiggestRemainingFont(pPrFontMemRec + 1, nPrFontsDL - i - 1, nil);
  359.                                             
  360.                 if (biggestRemaining <= remainingVM - pPrFontMemRec->vmUsage ) {
  361.  
  362.                     /** It fits, take care of it **/
  363.                     
  364.                     remainingVM -= pPrFontMemRec->vmUsage;
  365.                     pPrFontMemRec->used = true;
  366.  
  367.                     /** Mark the printer font as permanent **/
  368.  
  369.                     status = FHGetIndexedPrinterFont(hFHRec, pPrFontMemRec->theFont, pPrFontMemRec->prFontIndex, &printerFont, &offset);
  370.                     nrequire(status, failed_GetItem);
  371.                     
  372.                     printerFont->info |= fontIsPerm;                
  373.                 
  374.                 } else {
  375.                 
  376.                     break;                    // No more will fit. Get out of loop.
  377.                 
  378.                 }//end if
  379.             
  380.             }//end if
  381.             
  382.             ++pPrFontMemRec;
  383.         
  384.         }//end for
  385.         
  386. failed_noMemForFonts:
  387. failed_GetItem:
  388. failed_GetFont:    
  389.  
  390.     FHReleaseWorkspace(hFHRec, 0);
  391.  
  392. failed_WrkSpace:
  393.  
  394.         return(status);
  395.         
  396.     }//FHFindDocLevelFonts
  397.         
  398.  
  399.  
  400.  
  401.  
  402. //<FF>
  403. /*******************************************************
  404.  
  405.     Function: FHComputeDocFontSize:
  406.     
  407.     Function computes the memory used by a document font, 
  408.     excluding all of the glyphs that are printer resident.
  409.     
  410.     This function uses workHandle[1] so make sure it is
  411.     not in use during this call.
  412.     
  413.     hFHRec:                font handler record handle.
  414.     theFont:            font snapshot reference.
  415.     nGlyphs:            Number of glyphs in the font.
  416.     glyphBits:        document glyph bit usage array.
  417.     residentBits:    bit array for which glyphs are printer resident.
  418.     vmSize:                (returned) the vm used by the font.
  419.     
  420. ********************************************************/
  421. OSErr    FHComputeDocFontSize(TFontHandlerHdl hFHRec, fhFont theFont, long nGlyphs,
  422.                                                     unsigned long *glyphBits,    unsigned long *residentBits, long *vmSize)
  423.     {
  424.         OSErr                        status;
  425.         long                        size;
  426.         register short    i;
  427.         scalerStream        streamRecord;
  428.         Handle                    h;
  429.         unsigned long        *docMinusPrinterBits;
  430.         unsigned long        *pNewBits, *pDocBits, *pResidentBits;
  431.         gxFont                    theRealFont;
  432.         long                        dbIndex;
  433.         gxFontVariation    *theVariations;
  434.         Boolean                    lockedDB = false;
  435.         
  436.         theRealFont = FHGetSnapShotFont(hFHRec, theFont, &dbIndex);
  437.         
  438.         /** Allocate space for a new bit array **/
  439.         
  440.         size = (nGlyphs + 31) / 32;            // Size in longs of bit array.
  441.     
  442.         status = FHSetWorkHandleSize(hFHRec, 4 * size, 1, &h);
  443.         nrequire(status, failed_SetSize);
  444.         
  445.         HLockHi(h);
  446.         docMinusPrinterBits = (unsigned long*)*h;
  447.         
  448.         /*** Compute a new bit array that is the document glyphs excluding the printer-resident glyphs ***/
  449.  
  450.         pDocBits = glyphBits;
  451.         pResidentBits = residentBits;
  452.         pNewBits = docMinusPrinterBits;
  453.         for (i = size - 1; i >= 0; --i)
  454.             *pNewBits++ = *pDocBits++ & ~*pResidentBits++;
  455.  
  456.         /** Now compute the size by sending the stream message **/
  457.         
  458.         streamRecord.types = (*hFHRec)->legalStreamTypes;
  459.         streamRecord.targetVersion = (*hFHRec)->productDescription;
  460.         streamRecord.action = fontSizeQueryStreamAction;
  461.         streamRecord.info.font.encoding = nil;
  462.         streamRecord.info.font.name = nil;
  463.         streamRecord.info.font.glyphBits = (long*)docMinusPrinterBits;
  464.         
  465.         /** Set up the variations fields in the stream record.  eMainBits implies don't need snapshots **/
  466.  
  467.         if (dbIndex == eMainBits) {
  468.         
  469.             streamRecord.variationCount = selectAllVariations;
  470.             streamRecord.variations = nil;
  471.         
  472.         } else {
  473.         
  474.             status = FontDbaseLock((*hFHRec)->docDbase);                // Lock the font database so we can get pointer to variations.
  475.             nrequire(status, failed_dbLock);
  476.             lockedDB = true;
  477.             
  478.             status = FontDbaseGetGlyphBits((*hFHRec)->docDbase, theRealFont, dbIndex, nil, &theVariations);
  479.             nrequire(status, failed_GetVariations);
  480.             
  481.             streamRecord.variationCount = GXCountFontVariations(theRealFont);
  482.             streamRecord.variations = theVariations;
  483.         
  484.         }//end if
  485.         
  486.         status = (*hFHRec)->psDevice->StreamFont(theRealFont, &streamRecord);
  487.         nrequire(status, failed_Stream);
  488.  
  489.         *vmSize = streamRecord.memorySize;
  490.  
  491.         /** Accumulate what font type came back **/
  492.  
  493.         (*hFHRec)->documentStreamTypes |= streamRecord.types;
  494.  
  495. #if DEBUGLEVEL >= DEBUGFEEDBACK
  496.         dprintf(trace, "size query for %d returned %d bytes, bits: %X", theRealFont, *vmSize, docMinusPrinterBits);        
  497. #endif
  498.  
  499. failed_Stream:
  500. failed_GetVariations:
  501.  
  502.         if (lockedDB) {
  503.         
  504.             OSErr            saveStatus = FontDbaseUnlock((*hFHRec)->docDbase);
  505.             if (status == noErr)
  506.                 status = saveStatus;
  507.                 
  508.             ncheck(saveStatus);
  509.             
  510.         }//end if
  511.         
  512.  
  513. failed_dbLock:
  514.  
  515.  
  516.         //dprintf(notrace, "status: %d, size: %d", status, streamRecord.memorySize);
  517.  
  518.         FHReleaseWorkspace(hFHRec, 1);
  519.         
  520. failed_SetSize:
  521.  
  522.         return(status);
  523.     
  524.     }//FHComputeDocfontSize
  525.  
  526.  
  527. //<FF>
  528. /*************************************************
  529.  
  530.     Function: FHComputePrinterFontSize
  531.     
  532.     Function computes the vm size for a printer font record.
  533.     
  534.     hFHRec:                    Font Handler handle
  535.     printerFont:        pointer to a printer font record.
  536.     
  537.     Puts the memory used into the printer font record's 
  538.         vmUsage field.
  539.  
  540. ***************************************************/
  541. OSErr FHComputePrinterFontSize(TFontHandlerHdl hFHRec, TPrinterFontRec *printerFont)
  542.     {
  543.         OSErr                        status;
  544.         scalerStream        streamRecord;
  545.         unsigned long        *glyphBits;                    // Make copy of glyph bits because streaming can corrupt them.
  546.         Boolean                    lockedDB = false;
  547.         gxFontVariation    *theVariations;
  548.         
  549.         /** Copy the glyph usage data **/
  550.         
  551.         status = PrNewPtr((Ptr *) &glyphBits, printerFont->usageSize);
  552.         nrequire(status, failed_Alloc);
  553.         memcpy(glyphBits, printerFont->glyphUsage, printerFont->usageSize);
  554.     
  555.         streamRecord.types = (*hFHRec)->legalStreamTypes;
  556.         streamRecord.targetVersion = (*hFHRec)->productDescription;
  557.         streamRecord.action = fontSizeQueryStreamAction;
  558.         streamRecord.info.font.encoding = nil;
  559.         streamRecord.info.font.name = nil;
  560.         streamRecord.info.font.glyphBits = (long*)glyphBits;
  561.  
  562.         /** Set up the variations fields in the stream record.  eMainBits implies don't need snapshots **/
  563.         
  564.         if (printerFont->dbIndex == eMainBits) {
  565.         
  566.             streamRecord.variationCount = selectAllVariations;
  567.             streamRecord.variations = nil;
  568.             
  569.         } else {
  570.  
  571.             status = FontDbaseLock((*hFHRec)->docDbase);            // Lock the font database so we can get pointer to variations.
  572.             nrequire(status, failed_dbLock);
  573.             lockedDB = true;
  574.             
  575.             status = FontDbaseGetGlyphBits((*hFHRec)->docDbase, printerFont->theRealFont,
  576.                                                                                 printerFont->dbIndex, nil, &theVariations);
  577.             nrequire(status, failed_GetVariations);
  578.             
  579.             streamRecord.variationCount = GXCountFontVariations(printerFont->theRealFont);
  580.             streamRecord.variations = theVariations;
  581.         
  582.         }//end if
  583.  
  584.         status = (*hFHRec)->psDevice->StreamFont(printerFont->theRealFont, &streamRecord);
  585.         nrequire(status, failed_Stream);
  586.         
  587.         /** Accumulate what font type came back **/
  588.  
  589.         (*hFHRec)->documentStreamTypes |= streamRecord.types;
  590.     
  591.         printerFont->vmUsage = streamRecord.memorySize;
  592.  
  593. #if DEBUGLEVEL > DEBUGFEEDBACK
  594.         dprintf(trace, "size query for %d returned %d bytes", printerFont->theRealFont, streamRecord.memorySize);        
  595. #endif
  596.             
  597. failed_Stream:
  598. failed_GetVariations:
  599.     
  600.         if (lockedDB) {
  601.         
  602.             OSErr            saveStatus = FontDbaseUnlock((*hFHRec)->docDbase);
  603.             if (status == noErr)
  604.                 status = saveStatus;
  605.                         
  606.             ncheck(saveStatus);
  607.             
  608.         }//end if
  609.  
  610. failed_dbLock:
  611.  
  612.         DisposePtr((Ptr)glyphBits);
  613.  
  614. failed_Alloc:
  615.         return(status);
  616.     
  617.     }//FHComputePrinterFontSize
  618.